package service

import (
	"encoding/json"
	"errors"
	"github.com/sirupsen/logrus"
	"hcy-api/lib/id"
	"hcy-api/lib/jwt"
	"hcy-api/structs/idp"
	"hcy-api/structs/tables"
	"idp/global"
	"idp/listener"
	"idp/repository"
	"time"
)

var TaskService = new(taskService)

type taskService struct {
}

func (s taskService) AddTask(in idp.AddTaskDto, self jwt.CustomClaims) (err error) {
	// 将任务记录到系统中
	bs, err := json.Marshal(in.MapIds)
	if err != nil {
		logrus.Error(err)
		return err
	}
	m := &tables.IdpTask{
		Id:        id.GetSnowId(),
		Name:      in.Name,
		TaskType:  in.TaskType,
		StartTime: in.StartTime,
		EndTime:   in.EndTime,
		TaskRank:  in.TaskRank,
		MapIds:    string(bs),
		Details:   in.Details,
		Status:    tables.IdpTaskStatusForNormal,
		AutoCreateInfo: tables.AutoCreateInfo{
			Creator:   self.Nickname,
			CreatorId: self.UserID,
			CreatedAt: time.Now().Unix(),
		},
	}
	if err = repository.TaskRepository.CreateTask(m); err != nil {
		return err
	}
	global.TaskCatch.Store(m.Id, *m)
	// 将指令写到对应的缓存中
	_, err = s.LoadInstructByTask(*m)
	return err
}

// LoadInstructByTask 任务生效就加载相关指令的缓存, b -任务是否被触发
func (s taskService) LoadInstructByTask(task tables.IdpTask) (b bool, err error) {
	if task.StartTime < time.Now().Unix() && task.EndTime > time.Now().Unix() && task.Status == tables.IdpTaskStatusForNormal {
		b = true
		var ids []int64
		err = json.Unmarshal([]byte(task.MapIds), &ids)
		if err != nil {
			return
		}
		var inst idp.PluginInstruct
		inst, err = listener.InstructionUtils.TaskForFileAndProcess(task)
		if err != nil {
			return
		}
		// 写入指令缓存
		switch task.TaskRank {
		case tables.IdpTaskRankForFull:
			for k, _ := range listener.TcpSer.ClientMap {
				listener.InsertCatchInstruct(k, inst)
			}
		case tables.IdpTaskRankForBranch:
			var clientIds []int64
			clientIds, err = repository.BranchRepository.FindClientIdsByBranchId(ids)
			if err != nil {
				return
			}
			for _, v := range clientIds {
				if listener.IsOnline(v) {
					listener.InsertCatchInstruct(v, inst)
				}
			}
		case tables.IdpTaskRankForClient:
			for _, v := range ids {
				if listener.IsOnline(v) {
					listener.InsertCatchInstruct(v, inst)
				}
			}
		}
	}
	return
}

func (s taskService) CountResult(taskId int64) (r idp.CountTaskResult, err error) {
	var (
		coverNum  int64 // 任务覆盖的设备数量
		reportNum int64 // 完成上报的设备数量
		okNum     int64 // 符合检查要求的设备数量
		task      tables.IdpTask
	)
	if task, err = repository.TaskRepository.FindTaskById(taskId); err != nil {
		return
	}
	if coverNum, err = s.countTaskCoverNum(task); err != nil {
		return
	}
	if reportNum, err = repository.TaskRepository.CountTaskReportNum(taskId); err != nil {
		return
	}
	if okNum, err = repository.TaskRepository.CountTaskOkNum(taskId); err != nil {
		return
	}
	r.CoverNum = coverNum
	r.OkNum = okNum
	r.ReportNum = reportNum
	return
}

// countTaskCoverNum 统计任务覆盖的设备范围
func (s taskService) countTaskCoverNum(task tables.IdpTask) (num int64, err error) {
	switch task.TaskRank {
	case tables.IdpTaskRankForFull:
		if num, err = repository.ClientRepository.CountClientNum(); err != nil {
			return 0, err
		}
	case tables.IdpTaskRankForBranch:
		var ids []int64
		if err = json.Unmarshal([]byte(task.MapIds), &ids); err != nil {
			return 0, err
		}
		if num, err = repository.BranchRepository.CountClientNumByBranchIds(ids); err != nil {
			return 0, err
		}
	case tables.IdpTaskRankForClient:
		var ids []int64
		if err = json.Unmarshal([]byte(task.MapIds), &ids); err != nil {
			return 0, err
		}
		num = int64(len(ids))
	default:
		err = errors.New("未知任务类型")
	}
	return
}

// SyncTaskCatch 同步缓存任务，如果任务已经过期就删除，如果任务
func (s taskService) SyncTaskCatch(task tables.IdpTask) (err error) {
	// 如果任务以过期就删除缓存，状态还是正常就将其更新为过期
	if task.EndTime < time.Now().Unix() {
		if task.Status == tables.IdpTaskStatusForNormal {
			if err = repository.TaskRepository.UpdateTaskExpiredById(task.Id, tables.IdpTaskStatusForExpired); err != nil {
				return err
			}
		}
		if _, ok := global.TaskCatch.Load(task.Id); ok {
			global.TaskCatch.Delete(task.Id)
		}
	}
	// 任务状态不是正常就删除缓存
	if task.Status != tables.IdpTaskStatusForNormal {
		if _, ok := global.TaskCatch.Load(task.Id); ok {
			global.TaskCatch.Delete(task.Id)
		}
	}
	// 如果任务没过期，且任务状态是正常，说明这个任务被遗漏了，加入到缓存中
	if task.EndTime > time.Now().Unix() && task.Status == tables.IdpTaskStatusForNormal {
		if _, ok := global.TaskCatch.Load(task.Id); !ok {
			global.TaskCatch.Store(task.Id, task)
		}
	}
	return nil
}
